{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "93181bb2-841b-4aee-a1d1-8fb270e5cb24",
   "metadata": {},
   "source": [
    "# Model IO模块课程演练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dc23aec0-5f08-40ec-b988-6b4e19661a1f",
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: langchain in d:\\soft\\python\\lib\\site-packages (0.0.306)\n",
      "Requirement already satisfied: PyYAML>=5.3 in d:\\soft\\python\\lib\\site-packages (from langchain) (6.0)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in d:\\soft\\python\\lib\\site-packages (from langchain) (1.4.39)\n",
      "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in d:\\soft\\python\\lib\\site-packages (from langchain) (3.8.5)\n",
      "Requirement already satisfied: anyio<4.0 in d:\\soft\\python\\lib\\site-packages (from langchain) (3.7.1)\n",
      "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in d:\\soft\\python\\lib\\site-packages (from langchain) (0.6.1)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in d:\\soft\\python\\lib\\site-packages (from langchain) (1.33)\n",
      "Requirement already satisfied: langsmith<0.1.0,>=0.0.38 in d:\\soft\\python\\lib\\site-packages (from langchain) (0.0.41)\n",
      "Requirement already satisfied: numexpr<3.0.0,>=2.8.4 in d:\\soft\\python\\lib\\site-packages (from langchain) (2.8.4)\n",
      "Requirement already satisfied: numpy<2,>=1 in d:\\soft\\python\\lib\\site-packages (from langchain) (1.24.3)\n",
      "Requirement already satisfied: pydantic<3,>=1 in d:\\soft\\python\\lib\\site-packages (from langchain) (1.10.13)\n",
      "Requirement already satisfied: requests<3,>=2 in d:\\soft\\python\\lib\\site-packages (from langchain) (2.31.0)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in d:\\soft\\python\\lib\\site-packages (from langchain) (8.2.2)\n",
      "Requirement already satisfied: attrs>=17.3.0 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (22.1.0)\n",
      "Requirement already satisfied: charset-normalizer<4.0,>=2.0 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (2.0.4)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.2)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (4.0.2)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.8.1)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.3)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in d:\\soft\\python\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.2.0)\n",
      "Requirement already satisfied: idna>=2.8 in d:\\soft\\python\\lib\\site-packages (from anyio<4.0->langchain) (3.4)\n",
      "Requirement already satisfied: sniffio>=1.1 in d:\\soft\\python\\lib\\site-packages (from anyio<4.0->langchain) (1.2.0)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in d:\\soft\\python\\lib\\site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.20.1)\n",
      "Requirement already satisfied: typing-inspect<1,>=0.4.0 in d:\\soft\\python\\lib\\site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in d:\\soft\\python\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain) (2.1)\n",
      "Requirement already satisfied: typing-extensions>=4.2.0 in d:\\soft\\python\\lib\\site-packages (from pydantic<3,>=1->langchain) (4.8.0)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in d:\\soft\\python\\lib\\site-packages (from requests<3,>=2->langchain) (1.26.16)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in d:\\soft\\python\\lib\\site-packages (from requests<3,>=2->langchain) (2023.7.22)\n",
      "Requirement already satisfied: greenlet!=0.4.17 in d:\\soft\\python\\lib\\site-packages (from SQLAlchemy<3,>=1.4->langchain) (2.0.1)\n",
      "Requirement already satisfied: packaging>=17.0 in d:\\soft\\python\\lib\\site-packages (from marshmallow<4.0.0,>=3.18.0->dataclasses-json<0.7,>=0.5.7->langchain) (23.1)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in d:\\soft\\python\\lib\\site-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n"
     ]
    }
   ],
   "source": [
    "## 导入依赖库\n",
    "\n",
    "!pip install langchain"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "id": "bb802de5-723b-42d5-8c22-61f9e035f1b2",
   "metadata": {},
   "source": [
    "## 1. 什么是LCEL?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "869f9779-dcb5-483f-a70f-989de8a58646",
   "metadata": {},
   "source": [
    "LangChain LangChain Expression Language(LCEL) 表达式语言；设计用来创建和组合链式结构的语法系统，链式操作\n",
    "支持：并行处理、追踪、回调、批量、流式操作、同步等支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "id": "d96435af-97f9-4508-9064-90a7264ad066",
   "metadata": {},
   "source": [
    "## 2. Model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99415e02-03a3-4820-aa33-a65599cd4b50",
   "metadata": {},
   "source": [
    "### 2.1 Model的分类"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8bf2d692-f294-41fa-be0f-9bf3a9773827",
   "metadata": {},
   "source": [
    "LLMs: LangChain 的核心组件。LangChain并不提供自己的LLMs，而是为与许多不同的LLMs（OpenAI、Cohere、Hugging Face等）进行交互提供了一个标准\n",
    "接口。（类似于Completion，属于文本生成类模型的支持）\n",
    "\n",
    "Chat Models: 语言模型的一种变体。虽然聊天模型在内部使用了语言模型，但它们提供的接口略有不同。与其暴露一个“输入文本，输出文本”的API不同，\n",
    "它们提供了一个以“聊天消息”作为输入和输出的接口。(类似于Chat Completion，属于聊天会话类模型的支持)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a792d17e-4ff0-486b-b298-274f63ca7092",
   "metadata": {},
   "source": [
    "### 2.2 LLMs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5237b132-3665-49fc-96b9-fa4af20ebb50",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'\\n奥巴马担任美国总统的时间是2009年1月20日至2017年1月20日，共计8年。'"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_openai import OpenAI\n",
    "\n",
    "llm = OpenAI()\n",
    "\n",
    "#老的使用方式\n",
    "#llm(\"什么是机器学习？\")\n",
    "llm.invoke(\"奥巴马当了几年总统？\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3a3211c-3f7e-4de5-99c4-1253dcc33b2f",
   "metadata": {
    "tags": []
   },
   "source": [
    "OpenAI API 地址：https://api.python.langchain.com/en/latest/llms/langchain.llms.openai.OpenAI.html#langchain.llms.openai.OpenAI"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fc9ad88-f07c-41b3-a6c5-61e6896acd9d",
   "metadata": {},
   "source": [
    "### 2.3 Chat Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f7c3ffa8-4dbf-464a-872c-38322c67ce3f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "chat_model = ChatOpenAI(model=\"gpt-3.5-turbo-0125\")\n",
    "\n",
    "from langchain_core.messages import (\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    SystemMessage\n",
    ")\n",
    "\n",
    "# 设置模型角色，同时设置样例\n",
    "messages = [SystemMessage(content=\"你是一个智能助手\"),\n",
    " HumanMessage(content=\"第二十一届世界杯在哪儿举行的?\"),\n",
    " AIMessage(content=\"在俄罗斯\"),\n",
    " HumanMessage(content=\"冠军是哪个球队\")]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "0d91b4c1-a1e2-4b4c-b8ac-f3ae7f158105",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "AIMessage(content='2018年世界杯的冠军是法国队。他们在决赛中击败了克罗地亚队。', response_metadata={'token_usage': {'completion_tokens': 38, 'prompt_tokens': 67, 'total_tokens': 105}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None})"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_model.invoke(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7f1c7933-2cd9-4e44-aacc-8517590dc9d8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'法国队在2018年世界杯中获得冠军。'"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_model.invoke(messages).content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "21b197de-b369-4d49-988b-045948691f3c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='2018年世界杯的冠军是法国队。')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat_model(messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "551b5c58-c710-4979-a4d4-dcdc6580b143",
   "metadata": {},
   "source": [
    "ChatOpenAI API地址：https://api.python.langchain.com/en/latest/chat_models/langchain.chat_models.openai.ChatOpenAI.html#langchain.chat_models.openai.ChatOpenAI"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0a917a6-4cb5-40aa-8718-43b2372b219d",
   "metadata": {},
   "source": [
    "## 3.prompt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63c8cdb4-316b-4254-8514-67d94243b401",
   "metadata": {},
   "source": [
    "一个语言模型的提示是用户提供的一组指令或输入，用于引导模型的响应，帮助它理解上下文并生成相关和连贯的基于语言的输出，例如回答问题、完成句子或\n",
    "进行对话。\n",
    "\n",
    "提示模板（Prompt Templates）：参数化的模型输入\n",
    "\n",
    "示例选择器（Example Selectors）：动态选择要包含在提示中的示例"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af5ab6eb-4c9b-4892-a0f1-63b777b3512c",
   "metadata": {},
   "source": [
    "### 3.1 Prompt Templates"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a6abf87-8eb9-49bf-a4fa-611617d7424a",
   "metadata": {},
   "source": [
    "#### 1. use PromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6715235e-373d-4261-bf1c-d1f7478bddf9",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'Tell me a funny joke about chickens.'"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 可以动态传入参数\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "# 定义提示词模板\n",
    "prompt_template = PromptTemplate.from_template(\n",
    "    \"Tell me a {adjective} joke about {content}.\"\n",
    ")\n",
    "# 传入参数，格式化提示词模板\n",
    "prompt_template.format(adjective=\"funny\", content=\"chickens\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "5eb7a72c-4051-4078-a67e-ffc212a074ee",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'Tell me a joke'"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 也可以不传参数\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt_template = PromptTemplate.from_template(\"Tell me a joke\")\n",
    "prompt_template.format()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "04da45e0-0000-4145-8789-4a1b3a34587d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'\\n\\nWhy was the math book sad?\\n\\nBecause it had too many problems.'"
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm.invoke(prompt_template.format())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10aa929e-d943-435f-887b-245683c851b7",
   "metadata": {},
   "source": [
    "#### 2.use ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7d14135f-88e2-4010-b66a-7aa164f3dfe0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "AIMessage(content='My name is Bob. How can I assist you today?', response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 50, 'total_tokens': 62}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None})"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "chat_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"You are a helpful AI bot. Your name is {name}.\"),\n",
    "        (\"human\", \"Hello, how are you doing?\"),\n",
    "        (\"ai\", \"I'm doing well, thanks!\"),\n",
    "        (\"human\", \"{user_input}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "messages = chat_template.format_messages(name=\"Bob\", user_input=\"What is your name?\")\n",
    "\n",
    "chat_model.invoke(messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2fd8814f-db57-449a-9a2d-5def88242b08",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='我了解，人们常常会经历烦恼和困扰。但是，积极的态度和心态可以帮助我们应对困难和压力。让我来分享一些帮助你变得更积极的建议：\\n\\n1. 寻找支持：与朋友、家人或专业人士交流，分享你的烦恼，听取他们的建议和支持。\\n\\n2. 培养感恩之心：每天花一些时间思考你所拥有的，珍惜和感激这些东西。感恩之心可以帮助你更加积极地看待生活。\\n\\n3. 设定目标：制定一些具体的、可量化的目标，并制定实现这些目标的计划。追求目标可以给你带来成就感和动力。\\n\\n4. 培养健康的生活习惯：保持良好的饮食、充足的睡眠和适度的运动可以提升你的身体和心理健康。\\n\\n5. 积极思考：尝试改变消极的思维习惯，转而寻找积极的解释和观点。积极思考可以帮助你更好地应对挑战和困难。\\n\\n6. 寻找乐趣和爱好：找到一些你真正喜欢的活动或爱好，并定期参与其中。这样可以让你感到充实和快乐。\\n\\n7. 培养自我关爱：给自己一些时间和空间，关注自己的需求和感受。学会放松和照顾自己，这样你将更有能力面对困难。\\n\\n请记住，积极的态度需要时间和努力来培养。每天都尝试一些小的积极行为，逐渐改变你的思维方式。相信自己，你一定能够变得更积极和乐观！')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain.prompts import HumanMessagePromptTemplate\n",
    "from langchain_core.messages import SystemMessage\n",
    "\n",
    "chat_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        SystemMessage(\n",
    "            content=(\n",
    "                \"你是一个智能助手，让用户变得更积极\"\n",
    "            )\n",
    "        ),\n",
    "        HumanMessagePromptTemplate.from_template(\"{text}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "chat_model(chat_template.format_messages(text=\"我最近比较烦\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "846c5370-8c8b-4c6e-b8c6-87873e80e774",
   "metadata": {},
   "source": [
    "#### 3.Few-shot prompt templates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "cb5f24e1-25ed-4081-9397-84d1a471501a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain.prompts.few_shot import FewShotPromptTemplate\n",
    "from langchain.prompts.prompt import PromptTemplate\n",
    "\n",
    "examples  = [\n",
    "{\n",
    "\"question\": \"富兰克林·德拉诺·罗斯福和亚伯拉罕·林肯中哪个担任总统的时间更长？\",\n",
    "\"answer\":\n",
    "\"\"\"\n",
    "这里需要后续问题吗：是。\n",
    "后续问题：富兰克林·德拉诺·罗斯福担任了几年总统？\n",
    "中间答案：富兰克林·德拉诺·罗斯福担任了12年的总统。\n",
    "后续问题：亚伯拉罕·林肯则担任了几年总统？\n",
    "中间答案：亚伯拉罕·林肯则担任了5年的总统。\n",
    "因此最终答案是：富兰克林·德拉诺·罗斯福\n",
    "\"\"\"\n",
    "},\n",
    "{\n",
    "\"question\": \"百度的创始人是何时出生的？\",\n",
    "\"answer\":\n",
    "\"\"\"\n",
    "这里需要后续问题吗：是。\n",
    "后续问题：百度的创始人是谁？\n",
    "中间答案：百度的创始人是李彦宏。\n",
    "后续问题：李彦宏是什么时候出生的？\n",
    "中间答案：李彦宏于1968年11月17日出生。\n",
    "因此最终答案是：1968年11月17日\n",
    "\"\"\"\n",
    "},\n",
    "{\n",
    "\"question\": \"特雷西·麦克格雷迪和姚明，谁在NBA打的赛季多？\",\n",
    "\"answer\":\n",
    "\"\"\"\n",
    "这里需要后续问题吗：是。\n",
    "后续问题：特雷西·麦克格雷迪在NBA打了几个赛季？\n",
    "中间答案：特雷西·麦克格雷迪在NBA打了9个赛季。\n",
    "后续问题：姚明在NBA打了几个赛季？\n",
    "中间答案：姚明在NBA打了8个赛季。\n",
    "因此最终答案是：特雷西·麦克格雷迪\n",
    "\"\"\"\n",
    "}\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "265fefb6-52be-439a-83aa-6d47dfdf41e2",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Question: 富兰克林·德拉诺·罗斯福和亚伯拉罕·林肯中哪个担任总统的时间更长？\n",
      "\n",
      "这里需要后续问题吗：是。\n",
      "后续问题：富兰克林·德拉诺·罗斯福担任了几年总统？\n",
      "中间答案：富兰克林·德拉诺·罗斯福担任了12年的总统。\n",
      "后续问题：亚伯拉罕·林肯则担任了几年总统？\n",
      "中间答案：亚伯拉罕·林肯则担任了5年的总统。\n",
      "因此最终答案是：富兰克林·德拉诺·罗斯福\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 定义提示词模板\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"question\", \"answer\"], \n",
    "    template=\"Question: {question}\\n{answer}\")\n",
    "# 使用第一个样例作为参数 并输出打印\n",
    "print(example_prompt.format(**examples[0]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "20f133de-004a-451d-9edd-96c37902059c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Question: 富兰克林·德拉诺·罗斯福和亚伯拉罕·林肯中哪个担任总统的时间更长？\n",
      "\n",
      "这里需要后续问题吗：是。\n",
      "后续问题：富兰克林·德拉诺·罗斯福担任了几年总统？\n",
      "中间答案：富兰克林·德拉诺·罗斯福担任了12年的总统。\n",
      "后续问题：亚伯拉罕·林肯则担任了几年总统？\n",
      "中间答案：亚伯拉罕·林肯则担任了5年的总统。\n",
      "因此最终答案是：富兰克林·德拉诺·罗斯福\n",
      "\n",
      "\n",
      "Question: 百度的创始人是何时出生的？\n",
      "\n",
      "这里需要后续问题吗：是。\n",
      "后续问题：百度的创始人是谁？\n",
      "中间答案：百度的创始人是李彦宏。\n",
      "后续问题：李彦宏是什么时候出生的？\n",
      "中间答案：李彦宏于1968年11月17日出生。\n",
      "因此最终答案是：1968年11月17日\n",
      "\n",
      "\n",
      "Question: 特雷西·麦克格雷迪和姚明，谁在NBA打的赛季多？\n",
      "\n",
      "这里需要后续问题吗：是。\n",
      "后续问题：特雷西·麦克格雷迪在NBA打了几个赛季？\n",
      "中间答案：特雷西·麦克格雷迪在NBA打了9个赛季。\n",
      "后续问题：姚明在NBA打了几个赛季？\n",
      "中间答案：姚明在NBA打了8个赛季。\n",
      "因此最终答案是：特雷西·麦克格雷迪\n",
      "\n",
      "\n",
      "Question: 马云比马化腾大几岁？\n"
     ]
    }
   ],
   "source": [
    "prompt = FewShotPromptTemplate(\n",
    "    examples=examples,# 使用所有的样例\n",
    "    example_prompt=example_prompt,\n",
    "    suffix=\"Question: {input}\",\n",
    "    input_variables=[\"input\"]\n",
    ")\n",
    "\n",
    "print(prompt.format(input=\"马云比马化腾大几岁？\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "bfb9e0bd-13e2-4caa-9a49-ac5043fd5f61",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "'\\n\\n这里需要后续问题吗：是。\\n后续问题：特朗普的爸爸是谁？\\n中间答案：特朗普的爸爸是弗雷德·特朗普。\\n后续问题：弗雷德·特朗普的女儿是谁？\\n中间答案：弗雷德·特朗普的女儿是玛丽·安娜·特朗普。\\n后续问题：玛丽·安娜·特朗普的兄弟是谁？\\n中间答案：玛丽·安娜·特朗普的兄弟是唐纳德·特朗普。\\n因此最终答案是：唐纳德·特朗普'"
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm.invoke(prompt.format(input=\"特朗普的爸爸的女儿的兄弟是谁？\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5917952-4aad-45e1-ab43-e4a1933b2241",
   "metadata": {},
   "source": [
    "### 3.2 Example selectors"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2967ecb6-09a2-44d7-8f4c-fb7bd850e62f",
   "metadata": {},
   "source": [
    "#### 1.use Select by length"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "5c26f53d-e5ec-4993-8a68-db96a8e4e51f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.prompts import FewShotPromptTemplate\n",
    "from langchain.prompts.example_selector import LengthBasedExampleSelector\n",
    "\n",
    "\n",
    "# Examples of a pretend task of creating antonyms.\n",
    "examples = [\n",
    "    {\"input\": \"happy\", \"output\": \"sad\"},\n",
    "    {\"input\": \"tall\", \"output\": \"short\"},\n",
    "    {\"input\": \"energetic\", \"output\": \"lethargic\"},\n",
    "    {\"input\": \"sunny\", \"output\": \"gloomy\"},\n",
    "    {\"input\": \"windy\", \"output\": \"calm\"},\n",
    "]\n",
    "\n",
    "example_prompt = PromptTemplate(\n",
    "    input_variables=[\"input\", \"output\"],\n",
    "    template=\"Input: {input}\\nOutput: {output}\",\n",
    ")\n",
    "example_selector = LengthBasedExampleSelector(\n",
    "    # The examples it has available to choose from.\n",
    "    examples=examples,\n",
    "    # The PromptTemplate being used to format the examples.\n",
    "    example_prompt=example_prompt,\n",
    "    # The maximum length that the formatted examples should be.\n",
    "    # Length is measured by the get_text_length function below.\n",
    "    max_length=25,# 根据长度选择来选择不同的样例\n",
    "    # The function used to get the length of a string, which is used\n",
    "    # to determine which examples to include. It is commented out because\n",
    "    # it is provided as a default value if none is specified.\n",
    "    # get_text_length: Callable[[str], int] = lambda x: len(re.split(\"\\n| \", x))\n",
    ")\n",
    "dynamic_prompt = FewShotPromptTemplate(\n",
    "    # We provide an ExampleSelector instead of examples.\n",
    "    example_selector=example_selector,\n",
    "    example_prompt=example_prompt,\n",
    "    prefix=\"Give the antonym of every input\",\n",
    "    suffix=\"Input: {adjective}\\nOutput:\",\n",
    "    input_variables=[\"adjective\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "419f0428-26c3-4d1c-bfd1-b866460d9d94",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Give the antonym of every input\n",
      "\n",
      "Input: happy\n",
      "Output: sad\n",
      "\n",
      "Input: tall\n",
      "Output: short\n",
      "\n",
      "Input: energetic\n",
      "Output: lethargic\n",
      "\n",
      "Input: sunny\n",
      "Output: gloomy\n",
      "\n",
      "Input: windy\n",
      "Output: calm\n",
      "\n",
      "Input: big\n",
      "Output:\n"
     ]
    }
   ],
   "source": [
    "## 输入较短，所以给的示例多\n",
    "print(dynamic_prompt.format(adjective=\"big\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "5b3e5016-6758-4b2c-b7ea-11079242bb0a",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Give the antonym of every input\n",
      "\n",
      "Input: happy\n",
      "Output: sad\n",
      "\n",
      "Input: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else\n",
      "Output:\n"
     ]
    }
   ],
   "source": [
    "# 输入的内容长，給的示例少\n",
    "long_string = \"big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else\"\n",
    "print(dynamic_prompt.format(adjective=long_string))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47a40a61-0a15-48f5-916f-b6deb414fe04",
   "metadata": {},
   "source": [
    "## 4.Output parsers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92b244c2-7797-4d88-8981-b7ca2988d51c",
   "metadata": {},
   "source": [
    "语言模型输出文本。但是很多时候，你可能希望获得比纯文本更结构化的信息。这就是输出解析器的用处。\n",
    "\n",
    "输出解析器是帮助结构化语言模型响应的类。一个输出解析器必须实现两个主要方法：\n",
    "\n",
    "\"获取格式指令\"：返回一个包含语言模型输出应如何格式化的字符串的方法。\n",
    "\"解析\"：接受一个字符串（假设是语言模型的响应）并将其解析为某种结构的方法。\n",
    "然后还有一个可选的方法：\n",
    "\n",
    "\"带提示解析\"：接受一个字符串（假设是语言模型的响应）和一个提示（假设是生成此响应的提示），并将其解析为某种结构。提示主要是在OutputParser\n",
    "希望以某种方式重试或修复输出时提供的，它需要来自提示的信息来执行这些操作。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f183d9ac-74e1-485d-89a1-e10f3398c474",
   "metadata": {},
   "source": [
    "### 1.use List parser"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "369a7538-c32c-40e1-be17-0236e645877b",
   "metadata": {},
   "source": [
    "当您想返回一个以逗号分隔的项目列表时，可以使用此输出解析器。\n",
    "\n",
    "CommaSeparatedListOutputParser 解析逗号分隔列表的解析器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "88630646-a8d7-4ec1-9867-619dde8fa5fb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": "['chocolate',\n 'vanilla',\n 'strawberry',\n 'mint chocolate chip',\n 'cookies and cream']"
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.output_parsers import CommaSeparatedListOutputParser\n",
    "from langchain.prompts import PromptTemplate\n",
    "from langchain_openai import OpenAI\n",
    "\n",
    "model = OpenAI()\n",
    "\n",
    "parser = CommaSeparatedListOutputParser()\n",
    "format_instructions = parser.get_format_instructions()\n",
    "\n",
    "prompt = PromptTemplate(\n",
    "    template=\"List five {subject}.\\n{format_instructions}\",\n",
    "    input_variables=[\"subject\"],\n",
    "    partial_variables={\"format_instructions\": format_instructions}\n",
    ")\n",
    "\n",
    "\n",
    "## LCEL 链式表达式语言用法 (前一个的输入，作为后一个的输出)\n",
    "chain = prompt | model | parser\n",
    "chain.invoke({\"subject\": \"ice cream flavors\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbf1bdb0-c9be-4db1-b6ac-6e2be131086f",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
